<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>访问文档字段和特殊变量 | ElasticSearch 7.7 权威指南中文版</title>
	<meta name="keywords" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <meta name="description" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
	<script>
	var _link = 'modules-scripting-fields.html';
    </script>
</head>
<body>
<div class="main-container">
    <section id="content">
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.7/modules-scripting-fields.html" rel="nofollow" target="_blank">https://www.elastic.co/guide/en/elasticsearch/reference/7.7/modules-scripting-fields.html</a>, 原文档版权归 www.elastic.co 所有<br/>本地英文版地址: <a href="../en/modules-scripting-fields.html" rel="nofollow" target="_blank">../en/modules-scripting-fields.html</a></div>
                        <!-- start body -->
                  <div class="page_header">
<strong>重要</strong>: 此版本不会发布额外的bug修复或文档更新。最新信息请参考 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html" rel="nofollow">当前版本文档</a>。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch 权威指南 [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="modules-scripting.html">脚本</a></span>
»
<span class="breadcrumb-node">访问文档字段和特殊变量</span>
</div>
<div class="navheader">
<span class="prev">
<a href="modules-scripting-using.html">« 如何使用脚本</a>
</span>
<span class="next">
<a href="modules-scripting-security.html">脚本与安全 »</a>
</span>
</div>
<div class="chapter">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="modules-scripting-fields"></a>访问文档字段和特殊变量
</h2>
</div></div></div>
<p>
根据脚本的使用场合，它可以访问某些特殊变量和文档字段。
</p>
<h2>
<a id="_update_scripts"></a>更新(update)脚本
</h2>
<p>
在<a class="xref" href="docs-update.html" title="更新 API" rel="nofollow">更新(update)</a>、<a class="xref" href="docs-update-by-query.html" title="按查询更新 API" rel="nofollow">按查询更新(update-by-query)</a> 或 <a class="xref" href="docs-reindex.html" title="重新索引 API" rel="nofollow">重新索引(reindex)</a>中使用的脚本可以访问变量<code class="literal">ctx</code>，该变量公开了以下属性：
</p>
<div class="informaltable">
<table border="0" cellpadding="4px">
<colgroup>
<col>
<col>
</colgroup>
<tbody valign="top">
<tr>
<td valign="top">
<p>
<code class="literal">ctx._source</code>
</p>
</td>
<td valign="top">
<p>访问 <a class="xref" href="mapping-source-field.html" title="_source 字段" rel="nofollow"><code class="literal">_source</code>字段</a>。</p>
</td>
</tr>
<tr>
<td valign="top">
<p>
<code class="literal">ctx.op</code>
</p>
</td>
<td valign="top">
<p>应该应用于文档的操作：<code class="literal">index</code> 或 <code class="literal">delete</code>。</p>
</td>
</tr>
<tr>
<td valign="top">
<p>
<code class="literal">ctx._index</code> 等
</p>
</td>
<td valign="top">
<p>
访问<a class="xref" href="mapping-fields.html" title="元字段" rel="nofollow">文档元字段</a>，其中一些可能是只读的。
</p>
</td>
</tr>
</tbody>
</table>
</div>
<h2>
<a id="_search_and_aggregation_scripts"></a>搜索和聚合脚本
</h2>
<p>
除了每个搜索命中执行一次的<a class="xref" href="search-request-body.html#request-body-search-script-fields" title="脚本字段" rel="nofollow">脚本字段(script fields)</a>之外，搜索和聚合中使用的脚本将对每个可能匹配查询或聚合的文档执行一次。

取决于你有多少文档，这可能意味着数百万或数十亿次执行：这些脚本需要运行得很快！
</p>
<p>
可以使用<a class="xref" href="modules-scripting-fields.html#modules-scripting-doc-vals" title="Doc values">文档值(doc-values)</a>、 源(<a class="xref" href="modules-scripting-fields.html#modules-scripting-source" title="The document _source"><code class="literal">_source</code>)字段</a>或<a class="xref" href="modules-scripting-fields.html#modules-scripting-stored" title="Stored fields">存储的字段(stored fields)</a>从脚本中访问字段值，下面会对他们进行一一说明。
</p>
<h3>
<a id="scripting-score"></a>在脚本内获取文档的得分
</h3>
<p>
<a class="xref" href="query-dsl-function-score-query.html" title="Function score query"><code class="literal">function_score</code>查询、<a class="xref" href="search-request-body.html#request-body-search-sort" title="排序" rel="nofollow">基于脚本的排序</a>或<a class="xref" href="search-aggregations.html" title="聚合">聚合</a>中使用的脚本可以访问代表文档当前相关性分数的<code class="literal">_score</code>变量。
</p>
<p>
下面是一个在<a class="xref" href="query-dsl-function-score-query.html" title="函数评分查询"><code class="literal">function_score</code>查询</a>中使用脚本来改变每个文档的相关性评分(<code class="literal">_score</code>)的示例:
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT my_index/_doc/1?refresh
{
  "text": "quick brown fox",
  "popularity": 1
}

PUT my_index/_doc/2?refresh
{
  "text": "quick fox",
  "popularity": 5
}

GET my_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "script_score": {
        "script": {
          "lang": "expression",
          "source": "_score * doc['popularity']"
        }
      }
    }
  }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/598.console"></div>
<h3>
<a id="modules-scripting-doc-vals"></a>文档值(doc values)
</h3>
<p>
到目前为止，从脚本中访问字段值最快最有效的方法是使用<code class="literal">doc['field_name']</code>语法，该语法从文档值(<a class="xref" href="doc-values.html" title="doc_values" rel="nofollow">doc values</a>)中检索字段值。

文档值是按列式字段值存储的，默认情况下，除了<a class="xref" href="text.html" title="text数据类型" rel="nofollow">analyzed <code class="literal">text</code>字段</a><span class="remark">(会被分析的字段)</span>之外，所有字段都启用该存储方式。
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT my_index/_doc/1?refresh
{
  "cost_price": 100
}

GET my_index/_search
{
  "script_fields": {
    "sales_price": {
      "script": {
        "lang":   "expression",
        "source": "doc['cost_price'] * markup",
        "params": {
          "markup": 0.2
        }
      }
    }
  }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/599.console"></div>
<p>文档值只能返回“简单”的字段值，如numbers、dates、geo-points、terms等，如果字段是多值的，则返回这些值的数组。它不能返回JSON对象。</p>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<h3>缺失的字段</h3>
<p>
如果映射中缺少<code class="literal">field</code>，<code class="literal">doc['field']</code>将会引发错误。

在<code class="literal">painless</code>下，可以首先使用<code class="literal">doc.containsKey('field')</code>进行检查，以防止访问<code class="literal">doc</code>的映射。

不幸的是，没有办法在<code class="literal">expression</code>脚本中检查映射中是否存在该字段。
</p>
</div>
</div>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<h3>文档值和<code class="literal">text</code>字段</h3>
<p>
<br/>
<br/>
如果启用了<a class="xref" href="fielddata.html" title="fielddata" rel="nofollow"><code class="literal">fielddata</code></a>，则<code class="literal">doc['field']</code>语法也可以用于<a class="xref" href="text.html" title="Text datatype">分析的(analyzed)<code class="literal">text</code>字段</a>，但是请<span class="strong strong"><strong>注意</strong></span>：在<code class="literal">text</code>字段上启用 fielddata 需要将所有的词项加载到JVM堆中，这在内存和CPU方面的开销都很大。

在脚本中访问<code class="literal">text</code>字段没有什么意义。
</p>
</div>
</div>
<h3>
<a id="modules-scripting-source"></a>文档的源(<code class="literal">_source</code>)
</h3>
<p>
可以使用<code class="literal">_source.field_name</code>语法访问文档的源(<a class="xref" href="mapping-source-field.html" title="_source 字段" rel="nofollow"><code class="literal">_source</code></a>)。

<code class="literal">_source</code>作为映射的映射加载，因此对象字段中的属性可以像<code class="literal">_source.name.first</code>这样来访问。
</p>
<div class="important admon">
<div class="icon"></div>
<div class="admon_content">
<h3>首选文档值(doc-values)而非_source</h3>
<p>
<br/>
<br/>
访问<code class="literal">_source</code>字段比使用文档值(doc-values)要慢得多。

<code class="literal">_source</code>字段针对每个结果返回几个字段进行了优化，而文档值(doc values)针对访问许多文档中特定字段的值进行了优化。
</p>
<p>
当从搜索结果中为前10个命中生成<a class="xref" href="search-request-body.html#request-body-search-script-fields" title="脚本字段" rel="nofollow">脚本字段(script field)</a>时，使用<code class="literal">_source</code>是有意义的，但是对于其他搜索和聚合用例，总是首选使用文档值(doc values)。
</p>
</div>
</div>
<p>例如：</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT my_index
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text"
      },
      "last_name": {
        "type": "text"
      }
    }
  }
}

PUT my_index/_doc/1?refresh
{
  "first_name": "Barry",
  "last_name": "White"
}

GET my_index/_search
{
  "script_fields": {
    "full_name": {
      "script": {
        "lang": "painless",
        "source": "params._source.first_name + ' ' + params._source.last_name"
      }
    }
  }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/600.console"></div>
<h3>
<a id="modules-scripting-stored"></a>存储的字段(stored fields)
</h3>
<p>
<em>存储字段(Stored fields)</em>-在映射中明确标记为<a class="xref" href="mapping-store.html" title="store" rel="nofollow"><code class="literal">"store": true</code></a>的字段-可以使用<code class="literal">_fields['field_name'].value</code>或<code class="literal">_fields['field_name']</code>语法进行访问：
</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT my_index
{
  "mappings": {
    "properties": {
      "full_name": {
        "type": "text",
        "store": true
      },
      "title": {
        "type": "text",
        "store": true
      }
    }
  }
}

PUT my_index/_doc/1?refresh
{
  "full_name": "Alice Ball",
  "title": "Professor"
}

GET my_index/_search
{
  "script_fields": {
    "name_with_title": {
      "script": {
        "lang": "painless",
        "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
      }
    }
  }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/601.console"></div>
<div class="tip admon">
<div class="icon"></div>
<div class="admon_content">
<h3>存储的(stored)与源(<code class="literal">_source</code>)</h3>
<p>
<br/>
<br/>
<code class="literal">_source</code>字段只是一个特殊的存储的字段，所以性能和其他存储字段差不多。

<code class="literal">_source</code>提供了对被索引的原始文档主体的访问(包括区分<code class="literal">null</code>值与空字段、单值数组与普通标量等的能力)。
</p>
<p>
只有当<code class="literal">_source</code>非常大，并且访问一些小的存储字段比访问整个<code class="literal">_source</code>成本更低时，使用存储字段而不是<code class="literal">_source</code>字段才有意义。
</p>
</div>
</div>
</div>
<div class="navfooter">
<span class="prev">
<a href="modules-scripting-using.html">« 如何使用脚本</a>
</span>
<span class="next">
<a href="modules-scripting-security.html">Scripting and security »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>